package com.karateca.columbiaimports.http;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * This HTTP downloader implementation uses apache commons to do the download.
 * @author Andres Dominguez
 */
public class ApacheHttpDownloader extends HttpDownloaderImpl implements
        HttpDownloader
{
    /** Apache log. */
    private static final Log log = LogFactory.getLog(ApacheHttpDownloader.class);
    /**
     * Sets the socket timeout (SO_TIMEOUT) in milliseconds to be used when executing
     * the method. A timeout value of zero is interpreted as an infinite timeout.
     */
    public static final int SOCKET_TIMEOUT = 60000;

    /**
     * Creates a new instance of ApacheHttpDownloader
     * @param maxRetryAttempts maximum number of retires when the connection is lost.
     */
    public ApacheHttpDownloader(int maxRetryAttempts)
    {
        super(maxRetryAttempts);
    }

    /**
     * @see HttpDownloader#doGet(java.lang.String) 
     */
    @Override
    public String doGet(String pageUrl) throws Exception
    {
        String response = null;
        HttpClient client;
        GetMethod method;
        boolean downloadSuccessful = false;
        int retryCount = 0;
        int waitTime = 1000;
        byte[] responseBody;

        client = new HttpClient();
        client.getParams().setParameter(HttpClientParams.SO_TIMEOUT, SOCKET_TIMEOUT);
        // Create a method instance.
        method = new GetMethod(pageUrl);
        // Provide custom retry handler is necessary
        method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false));

        do
        {
            try
            {
                // Execute the method.
                int statusCode = client.executeMethod(method);

                if (statusCode != HttpStatus.SC_OK)
                {
                    log.error("Method failed: " + method.getStatusLine());
                }

                // Read the response body.
                responseBody = method.getResponseBody();
                response = new String(responseBody);

                checkPage(response.toString());
                downloadSuccessful = true;
            }
            catch (Exception e)
            {
                retryCount++;
                if (retryCount > this.maxRetryAttempts)
                {
                    // maximum number reached, give up
                    log.error("Reached maximum retry attempts");
                    throw e;
                }
                log.warn("Error in link [" + pageUrl + "] " + e.getMessage());
                log.info("Retry " + retryCount + ", trying to reconnect in " + waitTime);
                Thread.sleep(waitTime);
                waitTime *= 1.5;
            }
            finally
            {
                // Release the connection.
                method.releaseConnection();
            }
        }
        while (downloadSuccessful == false);

        // Remove new line characters
        return response.replaceAll("\n", "");
    }
}
